package com.caishi.lkx.user.api;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.caishi.lkx.common.BaseApi;
import com.caishi.lkx.common.context.RequireContext;
import com.caishi.lkx.common.ienum.DateType;
import com.caishi.lkx.common.role.Role;
import com.caishi.lkx.common.role.Roles;
import com.caishi.lkx.user.ienum.status.UserStatus;
import com.caishi.lkx.user.ienum.type.UserAccountType;
import com.caishi.lkx.user.ienum.type.UserType;
import com.caishi.lkx.user.model.*;
import com.caishi.lkx.user.service.*;
import com.caishi.lkx.user.vo.AgentUserListVo;
import com.zzw.common.Wrappers;
import com.zzw.common.entity.impl.BaseIntEntity;
import com.zzw.common.exception.BizException;
import com.zzw.common.exception.BizRuntimeException;
import com.zzw.common.utils.CommonUtil;

import com.caishi.lkx.order.ienum.status.OrderStatus;
import com.caishi.lkx.order.ienum.type.OrderType;
import com.caishi.lkx.order.model.OrderModel;
import com.caishi.lkx.order.service.IOrderService;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.temporal.TemporalAdjusters;
import java.util.*;
import java.util.stream.Collectors;

@Tag(name = "代理商用户相关接口")
@RestController
@RequestMapping("/user/cu/agent/user")
public class AgentUserApi extends BaseApi {
    @Resource
    private IAgentUserService agentUserService;
    @Resource
    private IUserService<UserModel> userService;
    @Resource
    private IPositionService positionService;
    @Resource
    private IActionRoleService actionRoleService;
    @Resource
    private IAgentLevelService agentLevelService;
    @Resource
    private IAgentRechargeService agentRechargeService;

    @Resource
    private IOrderService orderService;


    @GetMapping("/page")
    @Operation(summary = "代理商用户列表")
    @Roles({Role.admin, Role.maxAdmin})
    @RequireContext(value = com.caishi.lkx.common.context.Role.CHANNEL)
    public IPage<AgentUserModel> agentPage(@ModelAttribute Page<AgentUserModel> page,
                                           @ModelAttribute AgentUserModel model,
                                           @RequestParam(defaultValue = "true") Boolean vo,
                                           @RequestParam(defaultValue = "false") Boolean role,
                                           @RequestParam(defaultValue = "false") Boolean position,
                                           @RequestParam(defaultValue = "false") Boolean showLevel,
                                           @RequestParam(defaultValue = "false") Boolean showChildren
    ) {
        model.setBindGroupId(context.getGroupId());
        Map<String, Object> query = clearReturnEmptyStr(model.toMap());
        query.put("enable", false);
        IPage<AgentUserModel> result = agentUserService.search(clearReturnEmptyStr(query), page, page.isSearchCount());
        return result.setRecords(result.getRecords().parallelStream().map(d -> {
            String levelName = "";
            d.setMobile(CommonUtil.mobileSafe(d.getMobile()));
            UserModel byId = userService.getById(d.getCreatedBy());
            if (null != byId) {
                d.setCreatedByName(byId.getName());
            } else {
                d.setCreatedByName(d.getCreatedBy());
            }
            if (showLevel) {
                if (StrUtil.isNotBlank(d.getLevelId())) {
                    AgentLevelModel level = agentLevelService.getById(d.getLevelId());
                    if (null != level) {
                        levelName = level.getName();
                        d.setLevelName(level.getName());
                    }
                }
            }
            if (role) {
                d.setRoles(actionRoleService.selectUserRoles(d.getId()));
            }
            if (position) {
                d.setPositions(positionService.userHavePosition(d.getId()));
            }
            List<AgentUserModel> children = this.getChildren(d.getId(), role, position, vo, levelName, UserStatus.lock);
            d.setChildren(children);
            if (vo) {
                AgentUserListVo data = AgentUserListVo.model2Vo(d);
                data.setRoleNames(role ? d.getRoles().stream().map(ActionRoleModel::getName).collect(Collectors.toList()) : null);
                data.setPositionNames(position ? d.getPositions().stream().map(PositionModel::getName).collect(Collectors.toList()) : null);
//                data.setLoginData(loginInfoService.userLastLoginData(d.getId()));
                return data;
            }
            return d;
//            LoginInfoModel loginInfoModel = loginInfoService.selectUserLoginInfo(d.getId(), UserAccountType.username);
//            if (null != loginInfoModel) {
//                d.setUserName(loginInfoModel.getAccount());
//            }
        }).collect(Collectors.toList()));
    }

    @DeleteMapping("/delete")
    @Transactional
    public Boolean delete(@RequestParam String id) {
        List<AgentUserModel> agentUserModels = agentUserService.selectList(Wrappers.<AgentUserModel>lambdaQuery().eq(AgentUserModel::getParentId, id));
        if (!agentUserModels.isEmpty()) {
            throw new BizRuntimeException("存在子用户,请删除子用户");
        }
        return agentUserService.delete(id);
    }

    private List<AgentUserModel> getChildren(String id, Boolean role, Boolean position, Boolean vo, String levelName, UserStatus userStatus) {
        return agentUserService.selectList(Wrappers.<AgentUserModel>lambdaQuery().eq(AgentUserModel::getParentId, id)).parallelStream().map(d -> {
            AgentUserModel agentUserModel = d.userInfoCopy(userService.getById(d.getId()));
            UserModel byId = userService.getById(d.getCreatedBy());
            if (agentUserModel.getUserStatus().equals(userStatus)) return null;
            if (null != byId) {
                agentUserModel.setCreatedByName(byId.getName());
            } else {
                agentUserModel.setCreatedByName(d.getCreatedBy());
            }
            agentUserModel.setMobile(CommonUtil.mobileSafe(agentUserModel.getMobile()));
            agentUserModel.setLevelName(levelName);
            if (role) {
                agentUserModel.setRoles(actionRoleService.selectUserRoles(d.getId()));
            }
            if (position) {
                agentUserModel.setPositions(positionService.userHavePosition(d.getId()));
            }
            if (vo) {
                AgentUserListVo data = AgentUserListVo.model2Vo(d);
                data.setRoleNames(role ? agentUserModel.getRoles().stream().map(ActionRoleModel::getName).collect(Collectors.toList()) : null);
                data.setPositionNames(position ? agentUserModel.getPositions().stream().map(PositionModel::getName).collect(Collectors.toList()) : null);
//                data.setLoginData(loginInfoService.userLastLoginData(d.getId()));
                return data;
            }
            return agentUserModel;
        }).filter(ObjectUtil::isNotNull).collect(Collectors.toList());
    }

    @GetMapping("/u-list")
    @Operation(summary = "代理商管理员列表")
    @Roles({Role.onlyLogin})
    @RequireContext(value = com.caishi.lkx.common.context.Role.CHANNEL)
    public List<AgentUserModel> agentPage(@RequestParam(defaultValue = "10", required = false) Integer size,
                                          @RequestParam(required = false, defaultValue = "false") Boolean all,
                                          @RequestParam(required = false, defaultValue = "false") Boolean first) {
        return agentUserService.selectList(Wrappers.<AgentUserModel>lambdaQuery().eq((context.getGroupId() != null && context.getGroupId() != 0L),AgentUserModel::getBindGroupId, context.getGroupId()).isNull(first, AgentUserModel::getParentId), size)
                .parallelStream().peek(a -> a.setName(userService.selectName(a.getId()))).collect(Collectors.toList());


    }

    @GetMapping("/current-page")
    @Operation(summary = "代理商用户列表")
    @Roles({Role.onlyLogin})
    public IPage<AgentUserModel> currentagentPage(@ModelAttribute Page<AgentUserModel> page,
                                                  @ModelAttribute AgentUserModel model,
                                                  @RequestParam(defaultValue = "true") Boolean total,
                                                  @RequestParam(defaultValue = "true") Boolean vo,
                                                  @RequestParam(defaultValue = "false") Boolean role,
                                                  @RequestParam(defaultValue = "false") Boolean position,
                                                  @RequestParam(defaultValue = "false") Boolean showLevel
    ) {
        AgentUserModel parent = agentUserService.getById(userContext.currentUserId());
        if (null == parent) {
            return page;
        }

        if (StrUtil.isNotBlank(parent.getParentId())) {
            parent = agentUserService.getById(parent.getParentId());
        }
        parent = parent.userInfoCopy(userService.getById(parent.getId()));
        List<AgentUserModel> records = new ArrayList<>();
        records.add(parent);
        IPage<AgentUserModel> result = page.setRecords(records);
        result.setTotal(records.size());
        return result.setRecords(result.getRecords().parallelStream().map(d -> {
            String levelName = "";
            d.setMobile(CommonUtil.mobileSafe(d.getMobile()));
            if (role) {
                d.setRoles(actionRoleService.selectUserRoles(d.getId()));
            }
            if (position) {
                d.setPositions(positionService.userHavePosition(d.getId()));
            }
            if (showLevel) {
                if (StrUtil.isNotBlank(d.getLevelId())) {
                    AgentLevelModel level = agentLevelService.getById(d.getLevelId());
                    if (null != level) {
                        levelName = level.getName();
                        d.setLevelName(level.getName());
                    }
                }
            }
            List<AgentUserModel> children = this.getChildren(d.getId(), role, position, vo, levelName, null);
            d.setChildren(children);
            if (vo) {
                AgentUserListVo data = AgentUserListVo.model2Vo(d);
                data.setRoleNames(role ? d.getRoles().stream().map(ActionRoleModel::getName).collect(Collectors.toList()) : null);
                data.setPositionNames(position ? d.getPositions().stream().map(PositionModel::getName).collect(Collectors.toList()) : null);
//                data.setLoginData(loginInfoService.userLastLoginData(d.getId()));
                return data;
            }
            return d;
//            LoginInfoModel loginInfoModel = loginInfoService.selectUserLoginInfo(d.getId(), UserAccountType.username);
//            if (null != loginInfoModel) {
//                d.setUserName(loginInfoModel.getAccount());
//            }
        }).collect(Collectors.toList()));
    }


    @Operation(summary = "新增代理")
    @PostMapping("/edit/add")
    @RequireContext(value = com.caishi.lkx.common.context.Role.CHANNEL)
    public AgentUserModel AgentUseradd(@ModelAttribute AgentUserModel model, @RequestParam(required = false) List<String> roleIds,
                                       @RequestParam(required = false) List<String> positionCodes, String username, String password) throws BizException {
        model.addUserType(UserType.agent);
        model.setUserStatus(UserStatus.normal);
        model.setBindGroupId(context.getGroupId()==null?agentUserService.getById(model.getParentId()).getBindGroupId():0L);
        return agentUserService.addUser(model, roleIds, positionCodes, model.getMobile(), password, UserAccountType.username);
    }

    @Operation(summary = "代理信息修改")
    @PutMapping("/edit/update")
    public AgentUserModel agentuseredit(@ModelAttribute AgentUserModel entity, @RequestParam(required = false) List<String> roleIds,
                                        @RequestParam(required = false) List<String> positionCodes) {
        agentUserService.update(entity);
        actionRoleService.userSettingRolesByIds(entity.getId(), roleIds);
        List<Long> positionIds = new ArrayList<>();
        if (CollUtil.isNotEmpty(positionCodes)) {
            positionIds = positionService.selectList(Wrappers.<PositionModel>lambdaQuery().in(PositionModel::getCode, positionCodes))
                    .stream().map(BaseIntEntity::getId).collect(Collectors.toList());
        }

        positionService.userSettingPositionByIds(entity.getId(), positionIds);
        return entity;
    }

    @GetMapping("/edit/detail/{id}")
    public AgentUserModel adminEditDetail(@PathVariable String id, @RequestParam(defaultValue = "false") Boolean showChildren) {
        AgentUserModel model = agentUserService.getUserDetail(id);
        UserModel userModel = userService.getById(model.getId());
        if (null != userModel) {
            model.setCreatedByName(userModel.getName());
        }
        model.setRoles(actionRoleService.selectUserRoles(model.getId()));
        model.setPositions(positionService.userHavePosition(model.getId()));
        if (showChildren && StrUtil.isNotBlank(model.getParentId())) {
            AgentUserModel parent = agentUserService.getUserDetail(model.getParentId());
            model.setParent(parent);
        }
        return model;
    }

    @PostMapping("/enable/{status}/{id}")
    public void settingEnable(@PathVariable String id, @PathVariable Boolean status) {
        agentUserService.lockUser(status, id);
    }

    @GetMapping("/simpleList")
    public List<UserModel> simpleList(@RequestParam(defaultValue = "10") Long size) {
        return userService.selectList(Wrappers.<UserModel>lambdaQuery().apply("user_type & 64 = 64").last("limit " + size));

    }

    @GetMapping("/simpleDetail/{id}")
    public AgentUserModel simpleDetail(@PathVariable String id) {
        return agentUserService.getById(id);

    }

    @GetMapping("/current-agentAndDiscount")
    @Operation(summary = "获取当前用户的代理商/折扣信息")
    public AgentUserModel agentAndDiscount() {
        return agentUserService.getMainInfo(userContext.currentUserId());

    }


    @GetMapping("/index-count")
    @Roles({Role.onlyLogin})
    public Map<String, Object> indexCount(@RequestParam(value = "all", defaultValue = "true") Boolean all) {
        //累计充值
        long total = 0L;
        //余额
        long banace = 0L;
        //消费
        long consum = 0L;
        //退款
        long refund = 0L;
        long todayMoney = 0L;
        String userId = null;
        if (!all) {
            userId = userContext.currentUserId();
            AgentUserModel agentUserModel = agentUserService.getById(userId);
            if (null == agentUserModel) {
                return MapUtil.<String, Object>builder().put("total", total).put("todayNew", todayMoney).put("refund", refund).put("banace", banace).put("consum", consum).build();
            }
            if (StrUtil.isNotBlank(agentUserModel.getParentId())) {
                userId = agentUserModel.getParentId();
            }
        }
        List<String> list = this.getChildren(userId, false, false, false, "", null).parallelStream().map(AgentUserModel::getId).toList();
        List<String> userIds = new ArrayList<>(list);
        userIds.add(userId);
        List<AgentUserModel> agentModels = agentUserService.selectList(Wrappers.<AgentUserModel>lambdaQuery().select(AgentUserModel::getBanance, AgentUserModel::getAccumulativeRecharge, AgentUserModel::getCumulativeConsumption)
                .eq(StrUtil.isNotBlank(userId), AgentUserModel::getId, userId));
        total = agentModels.stream().mapToLong(AgentUserModel::getAccumulativeRecharge).sum();
        banace = agentModels.stream().mapToLong(AgentUserModel::getBanance).sum();
        consum = agentModels.stream().mapToLong(AgentUserModel::getCumulativeConsumption).sum();
        List<OrderModel> orderModels = orderService.selectList(Wrappers.<OrderModel>lambdaQuery().in(OrderModel::getCreatedBy, userIds).eq(OrderModel::getOrderStatus, OrderStatus.refundSuccess).select(OrderModel::getPrice));
        refund = orderModels.parallelStream().mapToLong(OrderModel::getPrice).sum();
        LocalDateTime start = LocalDate.now().atTime(0, 0, 0);
        LocalDateTime end = LocalDate.now().atTime(23, 59, 59);
        List<AgentRechargeModel> agentRechargeModels = agentRechargeService.selectList(Wrappers.<AgentRechargeModel>lambdaQuery().select(AgentRechargeModel::getAmount)
                .eq(StrUtil.isNotBlank(userId), AgentRechargeModel::getUserId, userId)
                .between(AgentRechargeModel::getCreatedTime, start, end));
        todayMoney = agentRechargeModels.stream().mapToLong(AgentRechargeModel::getAmount).sum();
        return MapUtil.<String, Object>builder().put("total", total).put("todayMoney", todayMoney).put("refund", refund).put("banace", banace).put("consum", consum).build();
    }

    @GetMapping("/index-line")
    @Roles({Role.onlyLogin})
    public Map<String, BigDecimal> indexLine(@RequestParam("startTime") LocalDateTime startTime, @RequestParam("endTime") LocalDateTime endTime, @RequestParam("timeType") String timeType, @RequestParam(value = "all", defaultValue = "true") Boolean all) {
        String userId = null;
        Map<String, BigDecimal> map = new HashMap<>();
        if (!all) {
            userId = userContext.currentUserId();
            AgentUserModel agentUserModel = agentUserService.getById(userId);
            if (StrUtil.isNotBlank(agentUserModel.getParentId())) {
                userId = agentUserModel.getParentId();
            }
        }

        String format = "yyyy-MM-dd";
        if ("year".equals(timeType)) {
            format = "yyyy-MM";
        }
        List<AgentRechargeModel> agentRechargeModels = agentRechargeService.selectList(Wrappers.<AgentRechargeModel>lambdaQuery()
                .select(AgentRechargeModel::getAmount, AgentRechargeModel::getCreatedTime)
                .eq(StrUtil.isNotBlank(userId), AgentRechargeModel::getUserId, userId)
                .between(AgentRechargeModel::getCreatedTime, startTime, endTime));
        String finalFormat = format;
        LinkedHashMap<String, Long> collect = agentRechargeModels.stream()
                .collect(Collectors.groupingBy(x -> LocalDateTimeUtil.format(x.getCreatedTime(), finalFormat), LinkedHashMap::new, Collectors.summingLong(AgentRechargeModel::getAmount)));

        collect.keySet().forEach(key -> {
            BigDecimal divide = new BigDecimal(collect.get(key)).divide(new BigDecimal("100"), 2, RoundingMode.HALF_UP);
            map.put(key, divide);
        });
        return map;
    }

    @GetMapping("open-sku-record")
    public Map<String, Object> openSkuRecord(@RequestParam(value = "all", defaultValue = "true") Boolean all, DateType dateType) {
        String userId = userContext.currentUserId();
        List<String> userIds = new ArrayList<>();
        if (all) {
            AgentUserModel agentUserModel = agentUserService.getById(userId);
            if (null != agentUserModel && agentUserModel.getParentId() == null) {
                List<String> list = agentUserService.selectList(Wrappers.<AgentUserModel>lambdaQuery().eq(AgentUserModel::getParentId, userId)).parallelStream().map(AgentUserModel::getId).toList();
                userIds.addAll(list);
            }
        }
        userIds.add(userId);
        LocalDateTime startTime = LocalDateTime.now().with(LocalTime.MIN);
        LocalDateTime endTime = LocalDateTime.now().with(LocalTime.MAX);
        //获取当日开课记录
        Long todayMoney = orderService.selectCount(Wrappers.<OrderModel>lambdaQuery().in(OrderModel::getCreatedBy, userIds)
                .ge(OrderModel::getOrderStatus, 10).lt(OrderModel::getOrderStatus, 23)
                .eq(OrderModel::getType, OrderType.openCourse)
                .between(OrderModel::getCreatedTime, startTime, endTime));
        //开课总数
        Long allCount = orderService.selectCount(Wrappers.<OrderModel>lambdaQuery().in(OrderModel::getCreatedBy, userIds)
                .ge(OrderModel::getOrderStatus, 10).lt(OrderModel::getOrderStatus, 23)
                .eq(OrderModel::getType, OrderType.openCourse));
        LocalDateTime dateStartTime = null;
        LocalDateTime dateEndTime = null;
        dateEndTime = LocalDateTime.now();
        switch (dateType) {
            case WEEK -> dateStartTime = dateEndTime.minusDays(7);
            case MONTH -> dateStartTime = LocalDateTime.now().with(TemporalAdjusters.firstDayOfMonth()).with(LocalTime.MIN);
            case YEAR -> dateStartTime = LocalDateTime.now().with(TemporalAdjusters.firstDayOfYear()).with(LocalTime.MIN);
        }
        List<OrderModel> models = orderService.selectList(Wrappers.<OrderModel>lambdaQuery().in(OrderModel::getCreatedBy, userIds)
                .select(OrderModel::getCreatedTime)
                .ge(OrderModel::getOrderStatus, 10).lt(OrderModel::getOrderStatus, 23)
                .eq(OrderModel::getType, OrderType.openCourse)
                .between(null != dateStartTime, OrderModel::getCreatedTime, dateStartTime, dateEndTime)
                .orderByAsc(OrderModel::getCreatedTime)
        );
        Map<LocalDate, Long> openSkuCount = new HashMap<>();
        if (!models.isEmpty()) {
            openSkuCount = this.openSkuCount(dateType, dateStartTime, dateEndTime, models);
        }
        return MapUtil.<String, Object>builder().put("todayMoney", todayMoney).put("allCount", allCount).put("openSkuDateCount", openSkuCount).build();
    }

    private Map<LocalDate, Long> openSkuCount(DateType dateType, LocalDateTime dateStartTime, LocalDateTime dateEndTime, List<OrderModel> models) {
        Map<LocalDate, Long> map = new HashMap<>();
        LocalDate endTime = dateEndTime.toLocalDate();
        LocalDate startTime;
        if (!dateType.equals(DateType.ALL)) {
            startTime = dateStartTime.toLocalDate();
        } else {
            startTime = models.get(0).getCreatedTime().toLocalDate().with(TemporalAdjusters.firstDayOfMonth());
        }
        if (dateType.equals(DateType.WEEK) || dateType.equals(DateType.MONTH)) {
            while (endTime.compareTo(startTime) >= 0) {
                LocalDate finalStartTime = startTime;
                long count = models.parallelStream().filter(m -> {
                    if (m.getCreatedTime().toLocalDate().compareTo(finalStartTime) == 0) {
                        return true;
                    } else {
                        return false;
                    }
                }).count();
                map.put(finalStartTime, count);
                startTime = startTime.plusDays(1);
            }
        } else if (dateType.equals(DateType.YEAR) || dateType.equals(DateType.ALL)) {
            while (endTime.compareTo(startTime) >= 0) {
                LocalDate finalStartTime = startTime;
                long count = models.parallelStream().filter(m -> {
                    if (m.getCreatedTime().toLocalDate().isAfter(finalStartTime) && m.getCreatedTime().toLocalDate().isBefore(finalStartTime.with(TemporalAdjusters.lastDayOfMonth()))) {
                        return true;
                    } else {
                        return false;
                    }
                }).count();
                map.put(finalStartTime, count);
                if (startTime.plusMonths(1).compareTo(endTime) >= 0 && startTime.compareTo(endTime) != 0) {
                    startTime = endTime;
                } else {
                    startTime = startTime.plusMonths(1);
                }
            }
        }
        return map;
    }
//    @Operation(summary = "代理商绑定平台")
//    @PutMapping("/bind-group")
//    public void bindGroup(@ModelAttribute AgentUserModel entity) {
//        agentUserService.update(null, Wrappers.<AgentUserModel>update()
//                .setSql("bind_group_ids='" + entity.getBindGroupIds()+"'")
//                .eq("id", entity.getId()));

    //}

//    同步代理商到分销体系，即加入到分销人员表里，同时改动的还有删除代理商与修改代理商接口
//    代理商数据不会太多，可批量执行
    @GetMapping("/sync-agent-to-distribute")
   public void syncAgentUserToDistribute(){

        agentUserService.syncAgentUserToDistribute();
//        INSERT INTO distribution_users (id, levels_id, created_at, updated_at)
//        SELECT
//        sub.id,
//                cau.level_id AS levels_id,
//        sub.created_time AS created_at,
//                NOW() AS updated_at
//        FROM cu_user_base AS sub
//        INNER JOIN cu_agent_user AS cau ON sub.id = cau.id
//        WHERE cau.deleted = 0
//        AND sub.deleted = 0
//        AND sub.user_type & 64 = 64
//        AND sub.user_status != 1
//        AND cau.parent_id IS NULL
//        AND NOT EXISTS (
//                SELECT 1 FROM distribution_users du WHERE du.id = sub.id
//        )
//        ORDER BY sub.created_time DESC
//        LIMIT 200, 100;


   }
}
